{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "text.ipynb",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "DweYe9FcbMK_"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "AVV2e0XKbJeX",
        "colab": {}
      },
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "sUtoed20cRJJ"
      },
      "source": [
        "# Загрузка текста"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1ap_W4aQcgNT"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/load_data/text\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Смотрите на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ru/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запустите в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ru/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Изучайте код на GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs/site/ru/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Скачайте ноутбук</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fj66ZXAzrJC2",
        "colab_type": "text"
      },
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "NWeQAo0Ec_BL"
      },
      "source": [
        "Это руководство предлагает пример того как использовать `tf.data.TextLineDataset` для загрузки примеров из текстовых файлов. `TextLineDataset` предназначен для создания набора данных из текстового файла, в которых каждый пример это строка текста в исходном файле. Это потенциально полезно для любой текстовых данных которые изначально строковые (например, поэзия или логи ошибок).\n",
        "\n",
        "В этом руководстве мы будем использовать три разных английских перевода одного и того же текста - \"Илиады\" Гомера, и обучим модель определять переводчика на основе одной строки из текста."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fgZ9gjmPfSnK"
      },
      "source": [
        "## Установка"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "baYFZMW_bJHh",
        "colab": {}
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "try:\n",
        "  # %tensorflow_version существует только в Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "import tensorflow as tf\n",
        "\n",
        "import tensorflow_datasets as tfds\n",
        "import os"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "YWVWjyIkffau"
      },
      "source": [
        "Тексты трех переводов выполнили:\n",
        "\n",
        " - [Вильям Купер](https://en.wikipedia.org/wiki/William_Cowper) — [текст](https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt)\n",
        "\n",
        " - [Эрл Эдвард](https://en.wikipedia.org/wiki/Edward_Smith-Stanley,_14th_Earl_of_Derby) — [текст](https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt)\n",
        "\n",
        "- [Сэмюель Батлер](https://en.wikipedia.org/wiki/Samuel_Butler_%28novelist%29) — [текст](https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt)\n",
        "\n",
        "Текстовые файлы использованные в этом руководстве были подвергнуты некоторым типичным задачам предварительной обработки, в основном удаление материала - шапка и футер документа, нумерация строк, заголовки глав. Скачайте эти файлы локально."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "4YlKQthEYlFw",
        "colab": {}
      },
      "source": [
        "DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'\n",
        "FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']\n",
        "\n",
        "for name in FILE_NAMES:\n",
        "  text_dir = tf.keras.utils.get_file(name, origin=DIRECTORY_URL+name)\n",
        "  \n",
        "parent_dir = os.path.dirname(text_dir)\n",
        "\n",
        "parent_dir"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "q3sDy6nuXoNp"
      },
      "source": [
        "## Загрузите текст в датасеты\n",
        "\n",
        "Переберите файлы, загружая каждый в свой датасет.\n",
        "\n",
        "Каждый пример нужно пометить индивидуально, так что используйте `tf.data.Dataset.map` чтобы применить функцию расставляющую метки каждому элементу. Она переберет каждую запись в датасете возвращая пару (`example, label`)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "K0BjCOpOh7Ch",
        "colab": {}
      },
      "source": [
        "def labeler(example, index):\n",
        "  return example, tf.cast(index, tf.int64)  \n",
        "\n",
        "labeled_data_sets = []\n",
        "\n",
        "for i, file_name in enumerate(FILE_NAMES):\n",
        "  lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir, file_name))\n",
        "  labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i))\n",
        "  labeled_data_sets.append(labeled_dataset)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "M8PHK5J_cXE5"
      },
      "source": [
        "Объедините эти размеченные наборы данных в один и перемешайте его.\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "6jAeYkTIi9-2",
        "colab": {}
      },
      "source": [
        "BUFFER_SIZE = 50000\n",
        "BATCH_SIZE = 64\n",
        "TAKE_SIZE = 5000"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Qd544E-Sh63L",
        "colab": {}
      },
      "source": [
        "all_labeled_data = labeled_data_sets[0]\n",
        "for labeled_dataset in labeled_data_sets[1:]:\n",
        "  all_labeled_data = all_labeled_data.concatenate(labeled_dataset)\n",
        "  \n",
        "all_labeled_data = all_labeled_data.shuffle(\n",
        "    BUFFER_SIZE, reshuffle_each_iteration=False)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "r4JEHrJXeG5k"
      },
      "source": [
        "Вы можете использовать `tf.data.Dataset.take` и `print`, чтобы посмотреть как выглядят пары `(example, label)`. Свойство `numpy` показывает каждое значение тензора."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gywKlN0xh6u5",
        "colab": {}
      },
      "source": [
        "for ex in all_labeled_data.take(5):\n",
        "  print(ex)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "5rrpU2_sfDh0"
      },
      "source": [
        "## Закодируйте текстовые строки числами\n",
        "\n",
        "Модели машинного обучения работают с числами, не словами, так что строковые значения необходимо конвертировать в списки с числами. Чтобы сделать это поставьте в соответствие каждому слову свое число.\n",
        "\n",
        "### Создайте словарь\n",
        "\n",
        "Сперва создайте словарь токенизировав текст в коллекцию отдельных отличающихся слов. Есть несколько способов сделать это и в TensorFlow и в Python. В этом учебнике:\n",
        "\n",
        "1. Переберите `numpy` значения всех примеров.\n",
        "2. Используйте `tfds.features.text.Tokenizer` чтобы разбить их на токены.\n",
        "3. Соберите эти токены в множество Python чтобы избавиться от дубликатов\n",
        "4. Получите размер словаря для последующего использования."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "YkHtbGnDh6mg",
        "colab": {}
      },
      "source": [
        "tokenizer = tfds.features.text.Tokenizer()\n",
        "\n",
        "vocabulary_set = set()\n",
        "for text_tensor, _ in all_labeled_data:\n",
        "  some_tokens = tokenizer.tokenize(text_tensor.numpy())\n",
        "  vocabulary_set.update(some_tokens)\n",
        "\n",
        "vocab_size = len(vocabulary_set)\n",
        "vocab_size"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0W35VJqAh9zs"
      },
      "source": [
        "### Закодируйте примеры\n",
        "\n",
        "Создайте кодировщик передав  `vocabulary_set` в `tfds.features.text.TokenTextEncoder`. Метод `encode` кодировщика берет строку текста и возвращает список чисел."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "gkxJIVAth6j0",
        "colab": {}
      },
      "source": [
        "encoder = tfds.features.text.TokenTextEncoder(vocabulary_set)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "v6S5Qyabi-vo"
      },
      "source": [
        "Вы можете посмотреть одну строку чтобы увидеть как выглядит результат работы кодировщика."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "jgxPZaxUuTbk",
        "colab": {}
      },
      "source": [
        "example_text = next(iter(all_labeled_data))[0].numpy()\n",
        "print(example_text)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "XoVpKR3qj5yb",
        "colab": {}
      },
      "source": [
        "encoded_example = encoder.encode(example_text)\n",
        "print(encoded_example)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "p9qHM0v8k_Mg"
      },
      "source": [
        "Теперь запустите кодировщик на датасете обернув его в `tf.py_function` и передав в метод `map` датасета."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "HcIQ7LOTh6eT",
        "colab": {}
      },
      "source": [
        "def encode(text_tensor, label):\n",
        "  encoded_text = encoder.encode(text_tensor.numpy())\n",
        "  return encoded_text, label\n",
        "\n",
        "def encode_map_fn(text, label):\n",
        "  return tf.py_function(encode, inp=[text, label], Tout=(tf.int64, tf.int64))\n",
        "\n",
        "all_encoded_data = all_labeled_data.map(encode_map_fn)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "_YZToSXSm0qr"
      },
      "source": [
        "## Разбейте датасет на тестовую и обучающую выборки\n",
        "\n",
        "Используйте `tf.data.Dataset.take` и `tf.data.Dataset.skip` чтобы создать небольшой тестовый и большой обучающий датасеты.\n",
        "\n",
        "Перед передачей в модель датасет должны быть разбиты на пакеты. Обычно количество записей в пакете и их размерность должно быть одинаковые."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "r-rmbijQh6bf",
        "colab": {}
      },
      "source": [
        "train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE)\n",
        "train_data = train_data.padded_batch(BATCH_SIZE, padded_shapes=([-1],[]))\n",
        "\n",
        "test_data = all_encoded_data.take(TAKE_SIZE)\n",
        "test_data = test_data.padded_batch(BATCH_SIZE, padded_shapes=([-1],[]))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Xdz7SVwmqi1l"
      },
      "source": [
        "Сейчас, `test_data` и `train_data` являются не коллекциями пар (`example, label`), а коллекциями пакетов. Каждый пакет это пара вида (*много примеров*, *много меток*) представленная в виде массивов.\n",
        "\n",
        "Чтобы проиллюстрировать:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "kMslWfuwoqpB",
        "colab": {}
      },
      "source": [
        "sample_text, sample_labels = next(iter(test_data))\n",
        "\n",
        "sample_text[0], sample_labels[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "UI4I6_Sa0vWu"
      },
      "source": [
        "Так как мы ввели новую кодировку токенов (нуль использовался для заполнения), размер словаря увеличился на единицу."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "IlD1Lli91vuc",
        "colab": {}
      },
      "source": [
        "vocab_size += 1"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "K8SUhGFNsmRi"
      },
      "source": [
        "## Постройте модель\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "QJgI1pow2YR9",
        "colab": {}
      },
      "source": [
        "model = tf.keras.Sequential()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "wi0iiKLTKdoF"
      },
      "source": [
        "Первый слой конвертирует целочисленные представления в плотные векторные вложения. См. руководство [Вложения слов] (../../tutorials/sequences/word_embeddings) для подробностей."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "DR6-ctbY638P",
        "colab": {}
      },
      "source": [
        "model.add(tf.keras.layers.Embedding(vocab_size, 64))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "_8OJOPohKh1q"
      },
      "source": [
        "Следующий слой является [Long Short-Term Memory](http://colah.github.io/posts/2015-08-Understanding-LSTMs/) слоем, который позволяет моедли понять слова в контексте других слов. Двунаправленная обертка LSTM позволяет ей выучить взаимодействие элементов как с предыдущими так и с последующими элементами."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "x6rnq6DN_WUs",
        "colab": {}
      },
      "source": [
        "model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "cdffbMr5LF1g"
      },
      "source": [
        "И наконец у нас есть серии из одной и более плотно связанных слоев, последний из которых - выходной слой. Выходной слой генерирует вероятность для всех меток. Та у которой большая вероятность и является предсказанием модели для этого примера."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "QTEaNSnLCsv5",
        "colab": {}
      },
      "source": [
        "# Один или более плотных слоев.\n",
        "# Отредактируйте список в строке `for` чтобы поэкспериментировать с размером слоев.\n",
        "for units in [64, 64]:\n",
        "  model.add(tf.keras.layers.Dense(units, activation='relu'))\n",
        "\n",
        "# Выходной слой. Первый аргумент - число меток.\n",
        "model.add(tf.keras.layers.Dense(3, activation='softmax'))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "zLHPU8q5DLi_"
      },
      "source": [
        "Наконец скомпилируйте модель. Для softmax категоризационной модели используйте `sparse_categorical_crossentropy` в виде функции потерь. Вы можете попробовать другие оптимизаторы, но `adam` очень часто используемая."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "pkTBUVO4h6Y5",
        "colab": {}
      },
      "source": [
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "DM-HLo5NDhql"
      },
      "source": [
        "## Обучите модель\n",
        "\n",
        "Наша модель, работающая на этих данных, дает достойные результаты (около 83%)."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "aLtO33tNh6V8",
        "colab": {}
      },
      "source": [
        "model.fit(train_data, epochs=3, validation_data=test_data)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "KTPCYf_Jh6TH",
        "colab": {}
      },
      "source": [
        "eval_loss, eval_acc = model.evaluate(test_data)\n",
        "\n",
        "print('\\nEval loss: {:.3f}, Eval accuracy: {:.3f}'.format(eval_loss, eval_acc))"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}